/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package modules.enderecamento.facade;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import modules.enderecamento.bo.CargoBO;
import modules.enderecamento.bo.ClienteBO;
import modules.enderecamento.bo.EnderecamentoBO;
import modules.enderecamento.bo.FornecedorBO;
import modules.enderecamento.bo.GruposAcessoBO;
import modules.enderecamento.bo.GruposProdutoBO;
import modules.enderecamento.bo.PaleteBO;
import modules.enderecamento.bo.PermissaoBO;
import modules.enderecamento.bo.ProdutoBO;
import modules.enderecamento.bo.RuaBO;
import modules.enderecamento.bo.TiposMovimentoBO;
import modules.enderecamento.bo.UsuarioBO;
import modules.enderecamento.exception.EspacoExcedidoPaleteException;
import modules.enderecamento.exception.EspacoExcedidoRuaException;
import modules.enderecamento.exception.PaleteNaoEnderecadoException;
import modules.enderecamento.exception.PaleteOcupadoException;
import modules.enderecamento.exception.SaldoInsuficienteException;
import modules.enderecamento.models.dto.Cargo;
import modules.enderecamento.models.dto.Cliente;
import modules.enderecamento.models.dto.Enderecamento;
import modules.enderecamento.models.dto.Entrada;
import modules.enderecamento.models.dto.Fornecedor;
import modules.enderecamento.models.dto.GruposAcesso;
import modules.enderecamento.models.dto.GruposProduto;
import modules.enderecamento.models.dto.Palete;
import modules.enderecamento.models.dto.Permissao;
import modules.enderecamento.models.dto.Produto;
import modules.enderecamento.models.dto.Rua;
import modules.enderecamento.models.dto.Saida;
import modules.enderecamento.models.dto.TiposMovimento;
import modules.enderecamento.models.dto.Usuario;
import modules.enderecamento.models.dto.custom.OcupacaoPalete;
import modules.enderecamento.models.dto.custom.OcupacaoRua;

/**
 *
 * @author Clezio
 */
public class WMSFacade {
    public boolean saveFornecedor(Fornecedor obj){
        return new FornecedorBO().save(obj);
    }

    public List<Fornecedor> obterFornecedores(String sql){
        return new FornecedorBO().getList(sql);
    }

    public Fornecedor obterFornecedorById(Integer id){
        return new FornecedorBO().retrieve(id);
    }

    public boolean deleteFornecedor(Fornecedor obterFornecedor) {
        return new FornecedorBO().delete(obterFornecedor);
    }

    public List<GruposProduto> obterGruposProdutos(String sql) {
        return new GruposProdutoBO().getList(sql);
    }

    public GruposProduto obterGruposProdutoById(Integer id) {
        return new GruposProdutoBO().retrieve(id);
    }

    public boolean saveGruposProduto(GruposProduto obj) {
        return new GruposProdutoBO().save(obj);
    }

    public boolean deleteGruposProduto(GruposProduto gruposProduto) {
        return new GruposProdutoBO().delete(gruposProduto);
    }

    public List<Palete> obterPaletes(String sql) {
        return new PaleteBO().getList(sql);
    }

    public Palete obterPaleteById(Integer id) {
        return new PaleteBO().retrieve(id);
    }

    public boolean savePalete(Palete obj) throws EspacoExcedidoPaleteException {
        return new PaleteBO().save(obj);
    }

    public boolean deletePalete(Palete obj) {
        return new PaleteBO().delete(obj);
    }

    public Rua obterRuaById(int id) {
        return new RuaBO().retrieve(id);
    }

    public List<Rua> obterRuas(String sql) {
        return new RuaBO().getList(sql);
    }

    public boolean saveRua(Rua obj) throws EspacoExcedidoRuaException {
        return new RuaBO().save(obj);
    }

    public boolean deleteRua(Rua obj) {
        return new RuaBO().delete(obj);
    }

    public List<Produto> obterProdutos(String sql) {
        return new ProdutoBO().getList(sql);
    }

    public Produto obterProdutoById(int id) {
        return new ProdutoBO().retrieve(id);
    }

    public boolean saveProduto(Produto obj) {
        return new ProdutoBO().save(obj);
    }

    public boolean deleteProduto(Produto obj) {
        return new ProdutoBO().delete(obj);
    }

    public Rua obterRuaByName(String text) {
        return new RuaBO().obterRuaByName(text);
    }

    public Produto obterProdutoByCodigo(String codigo) {
        return new ProdutoBO().obterProdutoByCodigo(codigo);
    }

    public boolean registrarEntrada(Entrada entrada,Boolean ignoreEspaco) throws EspacoExcedidoPaleteException, EspacoExcedidoRuaException {
        return new EnderecamentoBO().registrarEntrada(entrada,ignoreEspaco);
    }

    public List<Enderecamento> obterEnderecamento(String sql) {
        return new EnderecamentoBO().getList(sql);
    }

    public List<Enderecamento> getListEnderecamentoByPalete(Palete palete) {
        return new EnderecamentoBO().getListByPalete(palete);
    }

    public boolean moverPalete(Palete palete, Rua ruaDestino) throws EspacoExcedidoRuaException {
        return new PaleteBO().moverPalete(palete, ruaDestino);
    }

    public boolean registrarSaida(Saida saida) throws SaldoInsuficienteException {
        return new EnderecamentoBO().registrarSaida(saida);
    }

    public boolean checkProdutoPalete(Produto produto, Palete palete) {
        return new EnderecamentoBO().checkProdutoPalete(produto, palete);
    }

    public GruposAcesso obterGruposAcessoById(int id) {
        return new GruposAcessoBO().retrieve(id);
    }

    public List<GruposAcesso> obterGruposAcessos(String sql) {
        return new GruposAcessoBO().getList(sql);
    }

    public boolean saveGruposAcesso(GruposAcesso obj) {
        return new GruposAcessoBO().save(obj);
    }

    public boolean deleteGruposAcesso(GruposAcesso obj){
        return new GruposAcessoBO().delete(obj);
    }

    public List<Permissao> obterPermissoes(String sql) {
        return new PermissaoBO().getList(sql);
    }

    public Usuario obterUsuarioById(int id) {
        return new UsuarioBO().retrieve(id);
    }

    public List<Usuario> obterUsuarios(String sql) {
        return new UsuarioBO().getList(sql);
    }

    public boolean saveUsuario(Usuario obj) {
        return new UsuarioBO().save(obj);
    }

    public boolean deleteUsuario(Usuario usuario) {
        return new UsuarioBO().delete(usuario);
    }

    public List<OcupacaoRua> getListOcupacaoRuas(Rua ruaParametro, Integer percentualDisponivel, Integer percentualOcupado){
        List<OcupacaoRua> mapOcupacaoRuas = new ArrayList<OcupacaoRua>();
        List<Rua> ruas = null;
        if(ruaParametro != null){
            ruas = obterRuas("from Rua where id = "+ruaParametro.getId());
        }else{
            ruas = obterRuas("from Rua order by nome");
        }
        
        for (int i= 0; i < ruas.size(); i++) {
            Rua rua = ruas.get(i);
            int ocupacao = obterPaletes("from Palete where rua_id = "+rua.getId()).size();
            int disponivel = rua.getQuantidadePaletes() - ocupacao;
            boolean dentroCondicao = true;
            if(percentualDisponivel != null){
                Integer total = ocupacao + disponivel;
                if((disponivel * 100 / total) < percentualDisponivel){
                    dentroCondicao = false;
                }
            }else if(percentualOcupado != null){
                Integer total = ocupacao + disponivel;
                if((ocupacao * 100 / total) < percentualOcupado){
                    dentroCondicao = false;
                }
            }
            if(dentroCondicao){
                mapOcupacaoRuas.add(new OcupacaoRua(rua, ocupacao, disponivel));
            }
        }
        return mapOcupacaoRuas;
    }

    public List<OcupacaoPalete> getListOcupacaoPaletes(Rua ruaParametro, Palete paleteParametro, Integer percentualDisponivel, Integer percentualOcupado){
        List<OcupacaoPalete> ocupacaoPaletes = new ArrayList<OcupacaoPalete>();
        List<Enderecamento> enderecamentos = null;
        List<Palete>paletes = null;
        if(paleteParametro != null){
            paletes = obterPaletes("from Palete where id = "+ruaParametro.getId());
        }else{
            paletes = obterPaletes("from Palete order by id");
        }
        for (int x= 0; x < paletes.size(); x++) {
            Palete palete = paletes.get(x);
            enderecamentos = obterEnderecamento("from Enderecamento where palete_id = "+palete.getId());
            Rua rua = palete.getRua();
            boolean inCondicao = true;
            if(ruaParametro != null){
                if(rua == null){
                    inCondicao = false;
                }else if(ruaParametro.getId() != rua.getId()){
                    inCondicao = false;
                }
            }
            if(inCondicao){
                ocupacaoPaletes.add(new OcupacaoPalete(rua, palete, new Double(0), palete.getCubagem() - new Double(0)));
            }
            for (int i= 0; i < enderecamentos.size(); i++) {
                Enderecamento enderecamento = enderecamentos.get(i);
                Integer paleteId = enderecamento.getPalete().getId();
                Produto produto = enderecamento.getProduto();
                int qtde = enderecamento.getQuantidade();
                BigDecimal produtoAltura = produto.getAltura().divide(BigDecimal.valueOf(100));
                BigDecimal produtoComprimento = produto.getComprimento().divide(BigDecimal.valueOf(100));
                BigDecimal produtoLargura = produto.getLargura().divide(BigDecimal.valueOf(100));
                BigDecimal subTotal = (produtoAltura.multiply(produtoComprimento).multiply(produtoLargura));
                Double ocupacao = subTotal.doubleValue() * qtde;
                OcupacaoPalete ocupacaoPalete = getOcupacaoPaleteCaseExistList(ocupacaoPaletes,paleteId);
                inCondicao = true;
                if(ruaParametro != null){
                    if(ruaParametro.getId() != rua.getId()){
                        inCondicao = false;
                    }
                }
                if(inCondicao){
                    if(ocupacaoPalete != null){
                        Double novoValorOcupacao = ocupacaoPalete.getOcupado() + ocupacao;
                        Double novoValorDisponivel = palete.getCubagem() - novoValorOcupacao;
                        ocupacaoPalete.setOcupado(novoValorOcupacao);
                        ocupacaoPalete.setDisponivel(novoValorDisponivel);
                    }else{
                        ocupacaoPaletes.add(new OcupacaoPalete(rua, palete, ocupacao, palete.getCubagem() - ocupacao));
                    }
                }
            }
        }
        if(percentualDisponivel != null){
            removeNotInCondition(ocupacaoPaletes,percentualDisponivel,"DISPONIVEL");
        }else if(percentualOcupado != null){
            removeNotInCondition(ocupacaoPaletes,percentualOcupado,"OCUPACAO");
        }
        return ocupacaoPaletes;
    }

    private OcupacaoPalete getOcupacaoPaleteCaseExistList(List<OcupacaoPalete> ocupacaoPaletes, Integer paleteId) {
        for (int i = 0; i < ocupacaoPaletes.size(); i++) {
            if(ocupacaoPaletes.get(i).getPalete().getId() == paleteId){
                return ocupacaoPaletes.get(i);
            }
        }
        return null;
    }

    private void removeNotInCondition(List<OcupacaoPalete> ocupacaoPaletes, Integer percentual, String natureza) {
        List<OcupacaoPalete> listRemove = new ArrayList<OcupacaoPalete>();
        for (int i = 0; i < ocupacaoPaletes.size(); i++) {
            boolean dentroCondicao = true;
            OcupacaoPalete ocupacaoPalete = ocupacaoPaletes.get(i);
            Double ocupado = ocupacaoPalete.getOcupado();
            Double disponivel = ocupacaoPalete.getDisponivel();
            Double total = ocupado + disponivel;

            if(natureza.toUpperCase().equals("OCUPACAO")){
                if((ocupado * 100 / total) < percentual){
                    dentroCondicao = false;
                }
            }else if(natureza.toUpperCase().equals("DISPONIVEL")){
                if((disponivel * 100 / total) < percentual){
                    dentroCondicao = false;
                }
            }

            if(dentroCondicao == false){
                listRemove.add(ocupacaoPaletes.get(i));
            }
        }
        ocupacaoPaletes.removeAll(listRemove);
    }

    public boolean alterarSenha(Usuario usuario) {
        return new UsuarioBO().alterarSenha(usuario);
    }

    public boolean removeProdutosPalete(Integer paleteId) {
        return new EnderecamentoBO().removeProdutosPalete(paleteId);
    }

    public boolean removeProdutosRua(String ruaName) {
        return new EnderecamentoBO().removeProdutosRua(ruaName);
    }

    public boolean moverProdutoPalete(Palete paleteOrigem, Palete paleteDestino, Produto produto, Integer quantidade) throws SaldoInsuficienteException, EspacoExcedidoPaleteException, EspacoExcedidoRuaException {
        return new EnderecamentoBO().moverProdutoPalete(paleteOrigem, paleteDestino, produto, quantidade);
    }

    public boolean moverPaleteRua(Rua ruaOrigem, Rua ruaDestino, Palete palete) throws EspacoExcedidoRuaException {
        return new EnderecamentoBO().moverPaleteRua(ruaOrigem, ruaDestino, palete);
    }

    public List<Palete> getListPaleteEnderecadoVazio() {
        return new PaleteBO().getListPaleteEnderecadoVazio();
    }

    public boolean removerPaleteVazio(Palete palete) throws PaleteOcupadoException, PaleteNaoEnderecadoException {
        return new PaleteBO().removerPaleteVazio(palete);
    }

    public List<Cliente> listarClientes(String sql) {
        return new ClienteBO().getList(sql);
    }

    public boolean saveCliente(Cliente obj) {
        return new ClienteBO().save(obj);
    }

    public List<Cliente> obterClientes(String sql) {
        return new ClienteBO().getList(sql);
    }

    public Cliente obterClienteById(int id) {
        return new ClienteBO().retrieve(id);
    }

    public boolean deleteCliente(Cliente cliente) {
        return new ClienteBO().delete(cliente);
    }

    public List<TiposMovimento> obterTiposMovimentos(String sql) {
        return new TiposMovimentoBO().getList(sql);
    }

    public TiposMovimento obterTiposMovimentoById(int id) {
        return new TiposMovimentoBO().retrieve(id);
    }

    public List<Entrada> listarEntradasByData(Date date) {
        return new EnderecamentoBO().listarEntradasByData(date);
    }

    public Entrada obterEntradaById(Integer id) {
        return new EnderecamentoBO().obterEntradaById(id);
    }

    public boolean cancelarEntrada(Entrada entrada) {
        return new EnderecamentoBO().cancelarEntrada(entrada);
    }

    public Saida obterSaidaById(int id) {
        return new EnderecamentoBO().obterSaidaById(id);
    }

    public boolean cancelarEntrada(Saida saida) {
        return new EnderecamentoBO().cancelarSaida(saida);
    }

    public List<Saida> listarSaidasByData(Date date) {
        return new EnderecamentoBO().listarSaidasByData(date);
    }

    public Cargo obterCargoById(int id) {
        return new CargoBO().retrieve(id);
    }

    public boolean saveCargo(Cargo obj) {
        return new CargoBO().save(obj);
    }

    public List<Cargo> obterCargos(String sql) {
        return new CargoBO().getList(sql);
    }

    public boolean deleteCargo(Cargo cargo) {
        return new CargoBO().delete(cargo);
    }
}
